{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 决策树学习实验\n",
    "\n",
    "本项目将带你通过动手实践的方式，深入理解决策树算法的工作原理。我们将使用经典的 Iris 数据集，从数据加载到模型评估，完整体验机器学习流程。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 环境准备与库导入"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入必要的库\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn import datasets\n",
    "from sklearn.tree import DecisionTreeClassifier, plot_tree\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.metrics import accuracy_score, confusion_matrix, classification_report\n",
    "import seaborn as sns\n",
    "\n",
    "# 设置中文字体\n",
    "plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']\n",
    "plt.rcParams['axes.unicode_minus'] = False\n",
    "\n",
    "print(\"环境准备完成！\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 数据加载与探索"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载 Iris 数据集\n",
    "iris = datasets.load_iris()\n",
    "X = iris.data\n",
    "y = iris.target\n",
    "\n",
    "# 创建 DataFrame 便于查看\n",
    "df = pd.DataFrame(X, columns=iris.feature_names)\n",
    "df['target'] = y\n",
    "df['target_name'] = df['target'].map({0: 'Setosa', 1: 'Versicolor', 2: 'Virginica'})\n",
    "\n",
    "print(\"数据集基本信息：\")\n",
    "print(f\"样本数量: {len(df)}\")\n",
    "print(f\"特征数量: {len(iris.feature_names)}\")\n",
    "print(f\"类别数量: {len(iris.target_names)}\")\n",
    "print(\"\\n特征名称:\", iris.feature_names)\n",
    "print(\"类别名称:\", iris.target_names)\n",
    "\n",
    "# 显示前5条数据\n",
    "print(\"\\n数据预览：\")\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 数据统计信息\n",
    "print(\"数据统计信息：\")\n",
    "df.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查看各类别样本分布\n",
    "print(\"类别分布：\")\n",
    "class_distribution = df['target_name'].value_counts()\n",
    "print(class_distribution)\n",
    "\n",
    "# 可视化类别分布\n",
    "plt.figure(figsize=(8, 6))\n",
    "class_distribution.plot(kind='bar')\n",
    "plt.title('Iris 数据集类别分布')\n",
    "plt.xlabel('类别')\n",
    "plt.ylabel('样本数量')\n",
    "plt.xticks(rotation=45)\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 数据预处理与划分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 划分训练集和测试集\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "    X, y, test_size=0.3, random_state=42, stratify=y\n",
    ")\n",
    "\n",
    "print(\"数据划分结果：\")\n",
    "print(f\"训练集大小: {len(X_train)} 个样本\")\n",
    "print(f\"测试集大小: {len(X_test)} 个样本\")\n",
    "print(f\"训练集特征形状: {X_train.shape}\")\n",
    "print(f\"测试集特征形状: {X_test.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. 决策树模型训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建决策树分类器\n",
    "clf = DecisionTreeClassifier(\n",
    "    criterion='gini',        # 使用基尼系数作为划分标准\n",
    "    max_depth=3,            # 限制树的最大深度，防止过拟合\n",
    "    random_state=42         # 设置随机种子保证结果可重现\n",
    ")\n",
    "\n",
    "# 训练模型\n",
    "clf.fit(X_train, y_train)\n",
    "\n",
    "print(\"模型训练完成！\")\n",
    "print(f\"决策树深度: {clf.tree_.max_depth}\")\n",
    "print(f\"叶子节点数量: {clf.tree_.n_leaves}\")\n",
    "print(f\"特征数量: {clf.n_features_in_}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. 模型可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 可视化决策树\n",
    "plt.figure(figsize=(20, 10))\n",
    "plot_tree(\n",
    "    clf,\n",
    "    feature_names=iris.feature_names,\n",
    "    class_names=iris.target_names,\n",
    "    filled=True,\n",
    "    rounded=True,\n",
    "    fontsize=12\n",
    ")\n",
    "plt.title('决策树结构图', fontsize=16)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. 模型预测与评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在测试集上进行预测\n",
    "y_pred = clf.predict(X_test)\n",
    "\n",
    "# 计算准确率\n",
    "accuracy = accuracy_score(y_test, y_pred)\n",
    "print(f\"模型准确率: {accuracy:.4f} ({accuracy*100:.2f}%)\")\n",
    "\n",
    "# 详细分类报告\n",
    "print(\"\\n分类报告：\")\n",
    "print(classification_report(y_test, y_pred, target_names=iris.target_names))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成混淆矩阵\n",
    "cm = confusion_matrix(y_test, y_pred)\n",
    "\n",
    "# 可视化混淆矩阵\n",
    "plt.figure(figsize=(8, 6))\n",
    "sns.heatmap(\n",
    "    cm,\n",
    "    annot=True,\n",
    "    fmt='d',\n",
    "    cmap='Blues',\n",
    "    xticklabels=iris.target_names,\n",
    "    yticklabels=iris.target_names\n",
    ")\n",
    "plt.title('混淆矩阵')\n",
    "plt.xlabel('预测值')\n",
    "plt.ylabel('真实值')\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. 特征重要性分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取特征重要性\n",
    "feature_importance = pd.DataFrame({\n",
    "    'feature': iris.feature_names,\n",
    "    'importance': clf.feature_importances_\n",
    "}).sort_values('importance', ascending=False)\n",
    "\n",
    "print(\"特征重要性排序：\")\n",
    "print(feature_importance)\n",
    "\n",
    "# 可视化特征重要性\n",
    "plt.figure(figsize=(10, 6))\n",
    "sns.barplot(data=feature_importance, x='importance', y='feature')\n",
    "plt.title('特征重要性分析')\n",
    "plt.xlabel('重要性得分')\n",
    "plt.ylabel('特征')\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8. 模型参数调优实验"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 实验不同最大深度的影响\n",
    "depths = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "train_scores = []\n",
    "test_scores = []\n",
    "\n",
    "for depth in depths:\n",
    "    clf_depth = DecisionTreeClassifier(max_depth=depth, random_state=42)\n",
    "    clf_depth.fit(X_train, y_train)\n",
    "    \n",
    "    train_pred = clf_depth.predict(X_train)\n",
    "    test_pred = clf_depth.predict(X_test)\n",
    "    \n",
    "    train_scores.append(accuracy_score(y_train, train_pred))\n",
    "    test_scores.append(accuracy_score(y_test, test_pred))\n",
    "\n",
    "# 可视化不同深度的性能\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(depths, train_scores, 'bo-', label='训练集准确率')\n",
    "plt.plot(depths, test_scores, 'ro-', label='测试集准确率')\n",
    "plt.xlabel('树的最大深度')\n",
    "plt.ylabel('准确率')\n",
    "plt.title('决策树深度与准确率的关系')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 找出最佳深度\n",
    "best_depth = depths[np.argmax(test_scores)]\n",
    "print(f\"最佳深度: {best_depth}\")\n",
    "print(f\"最佳测试准确率: {max(test_scores):.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 9. 总结与思考"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"=== 实验总结 ===\")\n",
    "print(\"1. 决策树是一种直观易懂的机器学习算法\")\n",
    "print(\"2. 通过可视化可以清晰看到决策过程\")\n",
    "print(\"3. 树深度过大会导致过拟合\")\n",
    "print(\"4. 特征重要性帮助我们理解哪些特征对分类最有帮助\")\n",
    "print(\"5. 混淆矩阵可以详细分析模型的分类性能\")\n",
    "\n",
    "print(\"\\n=== 关键发现 ===\")\n",
    "print(f\"- 当前模型在测试集上的准确率为: {accuracy*100:.2f}%\")\n",
    "print(f\"- 最重要的特征是: {feature_importance.iloc[0]['feature']}\")\n",
    "print(f\"- 建议的树深度为: {best_depth}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
